﻿using System.Diagnostics;
using System.Linq;
using System.Windows.Forms;
using HossMvp.Core;
using HossMvp.WinForms;
using Sample.Models;

namespace Sample.Presenters
{
    public class MainPresenter : AbstractPresenter
    {
        private AbstractView view { get { return this.ViewManager.Views.First(); } }
        private AbstractModel document;
        private bool askededToSave;

        public MainPresenter(AbstractModelManager modelManager, AbstractViewManager viewManager)
            : base(modelManager, viewManager, new WinFormsCommandProcessor(new NameDecorator("Main")))
        {
            this.askededToSave = false;
            this.RegisterCommands();
        }

        #region Commands

        private void RegisterCommands()
        {
            var decortor = this.CommandProcessor.Decorator;

            // add commands to command processor - File
            this.CommandProcessor.RegisterCommand(decortor.NameOf<MainPresenter>(p => p.NewDocument)
                , this.NewDocument
                , () => true
                , this.AskForSaveDecorator);
            this.CommandProcessor.RegisterCommand(decortor.NameOf<MainPresenter>(p => p.OpenDocument)
                , this.OpenDocument
                , () => true
                , this.AskForSaveDecorator);
            this.CommandProcessor.RegisterCommand(decortor.NameOf<MainPresenter>(p => p.SaveDocument)
                , this.SaveDocument
                , () => this.isModfied);
            this.CommandProcessor.RegisterCommand(decortor.NameOf<MainPresenter>(p => p.CloseView)
                , this.CloseView
                , () => true
                , this.AskForSaveDecorator);
            this.CommandProcessor.RegisterCommand(decortor.NameOf<MainPresenter>(p => p.ExitApplication)
                , this.ExitApplication
                , () => true);

            // Edit                               
            this.CommandProcessor.RegisterCommand(decortor.NameOf<MainPresenter>(p => p.Preferences)
                , this.Preferences
                , () => true);

            // Help                               
            this.CommandProcessor.RegisterCommand(decortor.NameOf<MainPresenter>(p => p.About)
                , this.About
                , () => true);
        }

        //---------------- File --------------

        private void NewDocument(CommandContext context)
        {
            this.view.Action("NewFile").WithPresenter(this).Execute();
            this.document = this.ModelManager.Create<DocumentModel>("NewFile"
                , new DocumentModel.DocumentContentProvider("NewFile", new NameDecorator("NewFile")));
        }

        private void OpenDocument(CommandContext context)
        {
            var result = this.view.Action("OpenFile").Execute();
            if (result != null)
            {
                this.ModelManager.Remove(this.document);
                var filename = result.Get<string>("filename");
                this.document = this.ModelManager.Create<DocumentModel>(filename
                    , new DocumentModel.DocumentContentProvider(filename, new NameDecorator(filename)));
                result = this.document.Action("LoadFile").Execute();
                this.view.Action("LoadFile").WithArguments(result.Data).Execute();
            }
        }

        private void SaveDocument(CommandContext context)
        {
            var result = this.view.Action("SaveFile").Execute();
            result = this.document.Action("SaveFile").WithArguments(result.Data).Execute();
            this.view.Action("LoadFile").WithArguments(result.Data).Execute();
        }

        private void CloseView(CommandContext context)
        {
            this.askededToSave = true;
            this.view.Action("Close").Execute();
        }

        private void ExitApplication(CommandContext context)
        {
            var args = ((WinFormsCommandContext)context).Arguments;
            var formClosingArgs = (FormClosingEventArgs)args;
            var reason = formClosingArgs.CloseReason;

            // possible reasons are:
            // None,
            // WindowsShutDown,
            // MdiFormClosing, 
            // UserClosing, 
            // TaskManagerClosing, 
            // FormOwnerClosing,
            // ApplicationExitCall

            Debug.WriteLine("Close reason: {0}", reason);

            if (this.AskForSaveDecorator() == false)
            {
                formClosingArgs.Cancel = true;
                return;
            }

            if (this.document != null)
            {
                this.document.Action("PostClose").WithArgument("reason", reason).Execute();
            }

            if (this.view != null)
            {
                this.view.Action("PostClose").WithArgument("reason", reason).Execute();
            }

            // implement whatever finalization tasks are required here
        }

        //---------------- Edit --------------

        private void Preferences(CommandContext context)
        {
            var prefsPresenter = new PreferencesPresenter(new ModelManager(this), new ViewManager(this));

            // create form and view, then either directly work with the form, or execute an action on the view
            /*var form = */
            new PreferencesForm(prefsPresenter);
            /*form.Show();*/

            var prefsView = prefsPresenter.ViewManager.Views.Single(v => v.Name == "PreferencesView");
            var mainForm = ((WinFormsContentProvider)this.ViewManager.Views.First().Contents).Form;
            prefsView.Action("Show").WithArgument("parent", mainForm).Execute();
        }

        //---------------- Help --------------

        private void About(object param)
        {
            //var aboutPresenter = new AboutPresenter(new ModelManager(), new ViewManager(), new WinFormsCommandProcessor());
            var aboutPresenter = new AboutPresenter(this.ModelManager, this.ViewManager);

            // create form and view, then either directly work with the form, or execute an action on the view.
            // the last allows for some specific HossMvp preparations to take place before launching the view.
            // ReSharper disable once ObjectCreationAsStatement
            new AboutForm(aboutPresenter);
            var aboutView = aboutPresenter.ViewManager.Views.Single(v => v.Name == "AboutView");

            var mainForm = ((WinFormsContentProvider)this.ViewManager.Views.First().Contents).Form;
            aboutView.Action("Show").WithArgument("parent", mainForm).Execute();
        }

        #endregion Commands

        #region Helpers

        private bool isModfied
        {
            get
            {
                var modified = false;
                if (this.view != null)
                {
                    var result = this.view.Action("GetEditorStatus").Execute();
                    modified = result.Get<bool>("modified");
                }

                return modified;
            }
        }

        private bool AskForSaveDecorator()
        {
            if (this.isModfied && this.askededToSave == false)
            {
                var result = this.view.Action("AskForSave").Execute();
                var save = result != null ? result.Get<SaveResponse>("saveAnswer") : SaveResponse.No;
                switch (save)
                {
                    case SaveResponse.Yes:
                        this.SaveDocument(null);
                        break;

                    case SaveResponse.No:
                        break;

                    case SaveResponse.Cancel:
                        return false;
                }
            }

            return true;
        }

        #endregion Helpers
    }
}